package cn.gs.serializable.old;

// @author gs
import cn.gs.reflect.ProxyTool;
import cn.gs.util.stream.TokenReader;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

public class SerialArray implements ISerialEntity {

    List<ISerialEntity> entities;

    @Override
    public <T> T deserialize(Class<T> clazz) {
        if (Collection.class.isAssignableFrom(clazz)) {
            List list = new LinkedList();
            for (ISerialEntity i : entities) {
                Object o = i.deserialize();
                list.add(o);
            }
            try {
                T ins = clazz.newInstance();
                ((List) ins).addAll(list);
                return ins;
            } catch (Throwable ex) {
            }
            try {
                for (Constructor c : clazz.getConstructors()) {
                    if (c.getParameterTypes().length == 1 && List.class.isAssignableFrom(c.getParameterTypes()[0])) {
                        T ins = (T) c.newInstance(list);
                        return ins;
                    }
                }
            } catch (Throwable ex) {
            }
            try {
                return ProxyTool.create(list, clazz);
            } catch (Throwable ex) {
            }
        } else if (clazz.isArray()) {
            Object array = Array.newInstance(clazz.getComponentType(), entities.size());
            for (int i = 0; i < entities.size(); ++i) {
                Object o = entities.get(i).deserialize(clazz.getComponentType());
                Array.set(array, i, o);
            }
            return (T) array;
        }
        return null;
    }

    @Override
    public Object deserialize() {
        return deserialize(List.class);
    }

    @Override
    public boolean serialize(Object o) {
        if (o == null) {
            return false;
        }
        if (o instanceof Collection) {
            Collection c = (Collection) o;
            entities = new ArrayList<ISerialEntity>(c.size());
            for (Object f : c) {
                ISerialEntity e = SerializableTool.serialize(f);
                entities.add(e);
            }
            return true;
        } else if (o.getClass().isArray()) {
            int len = Array.getLength(o);
            entities = new ArrayList<ISerialEntity>(len);
            for (int i = 0; i < len; ++i) {
                Object f = Array.get(o, i);
                ISerialEntity e = SerializableTool.serialize(f);
                entities.add(e);
            }
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void write(Writer w) throws IOException {
        boolean b = false;
        w.write("[");
        for (ISerialEntity i : entities) {
            if (b) {
                w.write(",");
            } else {
                b = true;
            }
            i.write(w);
        }
        w.write("]");
    }

    @Override
    public boolean read(TokenReader reader) throws IOException, ClassNotFoundException {
        String c = reader.get();
        if (!"[".equals(c.trim())) {
            reader.back();
            return false;
        }
        entities = new LinkedList<ISerialEntity>();
        ISerialEntity e;
        while ((e = SerializableTool.read(reader)) != null) {
            entities.add(e);
            c = reader.get();
            if (!",".equals(c.trim())) {
                reader.back();
                break;
            }
        }
        c = reader.get();
        if (!"]".equals(c.trim())) {
            reader.back();
            return false;
        }
        return true;
    }

    @Override
    public String toString(String prefix) {
        StringWriter w = new StringWriter();
        w.write("[\n");
        for (ISerialEntity i : entities) {
            String s = i.toString(prefix + " ");
            w.write(s);
            w.write("\n");
        }
        w.write(prefix);
        w.write("]");
        return w.toString();
    }

    @Override
    public String toString() {
        return toString("");
    }
}
